<?php

use App\Constants\ErrorCode;
use App\Request\FormRequest;
use Hyperf\Context\Context;
use Hyperf\Filesystem\FilesystemFactory;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\HttpServer\Router\Dispatched;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Hyperf\Context\ApplicationContext;
use Hyperf\Collection\Arr;
use App\Constants\RequestSceneCode;
use function Hyperf\Support\make;
use function Hyperf\Translation\__;
use function Hyperf\Config\config;
use function Hyperf\Coroutine\co;
use function Hyperf\Coroutine\defer;

/**
 * Responses Function Library
 * User: zx
 * Date: 2023-02-21
 * Time: 15:41
 */
if (!function_exists('respond')) {
    /**
     * 响应
     * @param mixed|array $data
     * @param string|null $message
     * @param string|int $code
     * @param array $appends 附加字段
     * @return PsrResponseInterface
     */
    function respond(mixed $data=[], ?string $message=null, string|int $code=ErrorCode::SERVER_SUCCESS, array $appends=[]):PsrResponseInterface
    {
        $params = [
            'code' => $code,
            'message' => $message?:ErrorCode::getMessage($code),
            'data' => $data
        ];

        if ($appends) {
            $params = array_merge($params, $appends);
        }

        /** @var ResponseInterface $response */
        $response = make(ResponseInterface::class);
        if (Context::has('request_id')) {
            $response = $response->withAddedHeader('request-id', Context::get('request_id'));
        }
        return $response->json($params);
    }
}

if (!function_exists('sceneErr')) {
    /**
     * 场景错误信息
     * @param int $scene
     * @param string|null $message
     * @param int $code
     * @return PsrResponseInterface
     */
    function sceneErr(int $scene=0, ?string $message=null, int $code=ErrorCode::SERVER_FAILED):PsrResponseInterface
    {
        return respond([], $message?:RequestSceneCode::getMessage($scene), $code, [
            'scene' => $scene,
            'path' => Arr::get(RequestSceneCode::$pathMap, $scene, '')
        ]);
    }
}

if (!function_exists('message')) {
    /**
     * 响应消息
     * @param string|null $message
     * @param int $code
     * @return PsrResponseInterface
     */
    function message(?string $message=null, int $code=ErrorCode::SERVER_SUCCESS):PsrResponseInterface
    {
        return respond([], $message, $code);
    }
}

if (!function_exists('success')) {
    /**
     * 请求响应成功
     * @param mixed|array $data
     * @return PsrResponseInterface
     */
    function success(mixed $data=[]):PsrResponseInterface
    {
        return respond($data);
    }
}

if (!function_exists('failed')) {
    /**
     * 请求错误响应
     * @param string|null $message
     * @param int $code
     * @return PsrResponseInterface
     */
    function failed(?string $message=null, int $code=ErrorCode::SERVER_FAILED):PsrResponseInterface
    {
        return message($message, $code);
    }
}

if (!function_exists('internalError')) {
    /**
     * 服务错误响应
     * @param string|null $message
     * @param int $code
     * @return PsrResponseInterface
     */
    function internalError(?string $message=null, int $code=ErrorCode::SERVER_ERROR):PsrResponseInterface
    {
        return message($message, $code);
    }
}

if (!function_exists('accepted')) {
    /**
     * 消息已被放入队列
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function accepted(?string $message=null):PsrResponseInterface
    {
        return message($message, ErrorCode::SERVER_ACCEPTED);
    }
}

if (!function_exists('stored')) {
    /**
     * 创建成功
     * @param mixed|array $data
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function stored(mixed $data=[], ?string $message=null):PsrResponseInterface
    {
        return respond($data, $message?:__('response.stored'));
    }
}

if (!function_exists('updated')) {
    /**
     * 编辑成功
     * @param mixed|array $data
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function updated(mixed $data=[], ?string $message=null):PsrResponseInterface
    {
        return respond($data, $message?:__('response.updated'));
    }
}

if (!function_exists('notfound')) {
    /**
     * 资源不存在
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function notfound(?string $message=null):PsrResponseInterface
    {
        return message($message, ErrorCode::SERVER_NOT_FOUND);
    }
}

if (!function_exists('deleted')) {
    /**
     * 删除
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function deleted(?string $message=null):PsrResponseInterface
    {
        return message($message?:__('response.deleted'));
    }
}

if (!function_exists('power')) {
    /**
     * 权限信息
     * @param string|null $message
     * @return PsrResponseInterface
     */
    function power(?string $message=null):PsrResponseInterface
    {
        return message($message?:__('response.forbidden'), ErrorCode::SERVER_FORBIDDEN);
    }
}

/**
 * Files Function Library
 * User: zx
 * Date: 2023-02-21
 * Time: 15:41
 */
if (!function_exists('getDir')) {
    /**
     * 获取文件列表
     * @param string $path
     * @return array
     */
    function getFolderNameList(string $path):array
    {
        $files = scandir($path);
        $dirs = [];
        foreach ($files as $file) {
            if (!in_array($file, ['.','..']) && is_dir($path.'/'.$file)) {
                $dirs[] = $file;
            }
        }

        return $dirs;
    }
}

if (!function_exists('temp')) {
    /**
     * 创建临时文件,使用后销毁
     * @param string $fileStr
     * @param string $ext
     * @return false|resource
     */
    function temp(string $fileStr='', $ext='txt')
    {
        $tempPath = BASE_PATH.DIRECTORY_SEPARATOR.'runtime'.DIRECTORY_SEPARATOR.'temp'.DIRECTORY_SEPARATOR.date('Ymd');
        if (!is_dir($tempPath)) {
            mkdir($tempPath, 0766, true);
        }
        $filename = getMillisecond().".{$ext}";
        $path = $tempPath.DIRECTORY_SEPARATOR.$filename;
        $file = fopen($path, 'w+');
        fwrite($file, $fileStr);

        defer(function () use ($file, $path) {
            fclose($file);
            unlink($path);
        });
        return $file;
    }
}

if (!function_exists('delStoredFile')) {
    /**
     * 批量删除存储图片
     * @param $paths
     * @param string $adapterName
     * @return bool
     * @throws \League\Flysystem\FilesystemException
     */
    function delStoredFile($paths, $adapterName='qiniu'):void
    {
        co(function () use ($paths, $adapterName) { // 新增协程
            if (!is_array($paths)) {
                $paths = (array)$paths;
            }
            /** @var FilesystemFactory $factory */
            $factory = make(FilesystemFactory::class);
            $adapter = $factory->get($adapterName);
            foreach ($paths as $path) {
                $blah = parse_url($path);
                $uri = trim($blah['path'], '/');
                if ($adapter->has($uri)) {
                    $adapter->delete($uri);
                }
            }
        });
    }
}

/**
 * Request Function Library
 * User: zx
 * Date: 2023-02-21
 * Time: 15:41
 */

if (!function_exists('getAuthorization')) {
    /**
     * 获取授权token
     * @param false $isPrefix 是否包含前缀
     * @return string
     */
    function getAuthorization($isPrefix=false):string
    {
        $request = make(ServerRequestInterface::class);
        $header = $request->getHeader('authorization');
        $token = '';
        if ($header
            && preg_match('/'.config('jwt.prefix').'\s*(\S+)\b/i', $header[0], $matches)
        ) {
            $token = $matches[1];
        }

        return $isPrefix?config('jwt.prefix').' '.$token:$token;
    }
}

if (!function_exists('getInfo')) {
    /**
     * 获取应用用户详情
     * @param string $app
     * @return mixed|string
     */
    function getInfo(string $app=null, ?string $key=null)
    {
        if (null === $app) $app = getApp();
        $appName = $app.'Info';
        $appInfo = Context::get($appName);
        if (!$appInfo) {
            throw new \App\Exception\InvalidRequestException(__('response.unauthorized'),ErrorCode::SERVER_UNAUTHORIZED);
        }

        return $key?$appInfo[$key]:$appInfo;
    }
}

if (!function_exists('getApp')) {
    /**
     * 获取APP详情
     * @return string
     */
    function getApp()
    {
        /** 是否为请求状态 */
        if (!Context::get(ServerRequestInterface::class)) {
            return '';
        }
        /** @var FormRequest $request */
        $request = make(FormRequest::class);
        return strtolower($request->appName());
    }
}

if (!function_exists('getAction')) {
    /**
     * 获取当前请求方法名
     * @return mixed
     */
    function getAction()
    {
        /** @var FormRequest $request */
        $request = make(FormRequest::class);
        return $request->getAction();
    }
}

if (!function_exists('getPath')) {
    /**
     * 获取当前请求路径
     * @return string
     */
    function getPath():string
    {
        /** @var FormRequest $request */
        $request = make(FormRequest::class);
        return $request->getPath();
    }
}

if (!function_exists('getShop')) {
    /**
     * 获取应用店铺
     * @param string|null $key
     * @return mixed|\App\Model\Shop\Shop
     */
    function getShop(string $key=null)
    {
        $shopModel = Context::get('shopModel');

        return $key?$shopModel->$key:$shopModel;
    }
}

if (!function_exists('getRequestHandler')) {
    /**
     * 获取请求信息
     * @return mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    function getRequestHandler()
    {
        $request = ApplicationContext::getContainer()->get(FormRequest::class);

        return $request->getAttribute(Dispatched::class)->handler;
    }
}

if (!function_exists('getDomain')) {
    /**
     * 获取当前域名
     * @return string
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    function getDomain():string
    {
        /** 是否为请求状态 */
        if (!Context::get(ServerRequestInterface::class)) {
            return config('domain');
        }
        $request = ApplicationContext::getContainer()->get(FormRequest::class);
        return $request->domain();
    }
}

if (!function_exists('getUrl')) {
    /**
     * 获取URL
     * @param string $route
     * @param string $domain
     * @return string
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    function getUrl(string $route='', string $domain=''):string
    {
        if (!$domain) {
            $domain = getDomain();
        }
        return $domain.'/'.$route;
    }
}

if (!function_exists('getHost')) {
    /**
     * 获取当前域名
     * @return string
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    function getHost(): string
    {
        $request = ApplicationContext::getContainer()->get(\App\Request\FormRequest::class);

        return $request->getHost();
    }
}

if (!function_exists('getIp')) {
    /**
     * 获取IP
     * @return string
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    function getIp() :string
    {
        $request = ApplicationContext::getContainer()->get(\App\Request\FormRequest::class);

        return $request->ip();
    }
}

/**
 * Array Function Library
 * User: zx
 * Date: 2023-02-21
 * Time: 15:41
 */
if (!function_exists('yieldArr')) {
    /**
     * 协程
     * @param array $array
     * @return Generator
     */
    function yieldArr(array $array):Generator
    {
        foreach ($array as $item) {
            yield $item;
        }
    }
}

/**
 * Time Function Library
 * User: zx
 * Date: 2023-02-21
 * Time: 15:41
 */
if (!function_exists('getMillisecond')) {
    /**
     * 获取毫秒级时间戳
     * @param bool $isTimestamp 是否带时间戳
     * @return float
     */
    function getMillisecond(bool $isTimestamp=true):float
    {
        [$s1, $s2] = explode(' ', microtime());
        $time = floatval($s1) * 1000;
        if (true === $isTimestamp) {
            $time = (floatval($s1) + floatval($s2)) * 1000;
        }
        return (float)sprintf('%.0f', $time);
    }
}

if (!function_exists('getMicrosecond')) {
    /**
     * 获取微秒级时间戳
     * @return array [微秒,时间戳]
     */
    function getMicrosecond():array
    {
        [$s1, $s2] = explode(' ', microtime());
        $micro = sprintf('%06d', $s1 * 1000000);
        return [
            $micro,
            (float)$s2
        ];
    }
}

if (!function_exists('timeDiff')) {
    /**
     * 获取两个时间差集秒数
     * @param string $start
     * @param string $end
     * @return int
     * @throws Exception
     */
    function timeDiffSec(string $start='now', string $end='now'):int
    {
        $datetime = new \DateTimeImmutable($start);
        $diff = $datetime->diff(new DateTimeImmutable($end));

        return intval($diff->format('%r').(
                ($diff->s)+
                (60*($diff->i))+
                (60*60*($diff->h))+
                (24*60*60*($diff->d))+ // days (no errors)
                (30*24*60*60*($diff->m))+ // months (???)
                (365*24*60*60*($diff->y)) // years (???)
            ));
    }
}

/**
 * Check Match Function Library
 * User: zx
 * Date: 2023-05-11
 * Time: 15:41
 */
if (!function_exists('checkEmail')) {
    /**
     * 检查邮箱格式
     * @param string $email
     * @return bool
     */
    function checkEmail(string $email):bool
    {
        return is_int(preg_match('/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/', $email));
    }
}

if (!function_exists('checkMobile')) {
    /**
     * 检查手机号码格式
     * @param string $mobile
     * @return bool
     */
    function checkMobile(string $mobile):bool
    {
        return is_int(preg_match('/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/', $mobile));
    }
}

/**
 * Logs Function Library
 * User: zx
 * Date: 2023-05-11
 * Time: 15:41
 */
if (!function_exists('logs')) {
    /**
     * 日志记录
     * @param $message
     * @param string $name
     * @param array $context
     * @param string $action
     */
    function logs($message, string $name='info', array $context = [], string $action='info', array $processor=[]):void
    {
        // 线上环境
        if (config('app_env') === 'pro') {
            return ;
        }

        /** 是否为 Cli */
        if (!Context::has(ServerRequestInterface::class)) {
            $name = 'cli';
        }

        defer(function () use ($message, $name, $context, $action, $processor) {
            /** @var \Hyperf\Logger\LoggerFactory $loggerFactory */
            $loggerFactory = make(\Hyperf\Logger\LoggerFactory::class);
            $logger = $loggerFactory->get($name);
            $requestIdProcessor = new \App\Process\Logger\RequestIdProcessor();
            $logger->pushProcessor($requestIdProcessor);
            foreach ($processor as $item) {
                $logger->pushProcessor($item);
            }
            if ($message instanceof Throwable) {
                $errData = [
                    'ErrorMessage' => $message->getMessage()
                ];
                if (!$message instanceof \App\Exception\InvalidRequestException && !$message instanceof \App\Exception\InternalException) {
                    $errData['ErrorTrace'] = $message->getTraceAsString();
                } else {
                    $errData['ErrorCode'] = $message->getCode();
                }
                foreach ($errData as $key => $errDatum) {
                    $logger->error("{$key}：[{$errDatum}]", $context);
                }
            } elseif (is_array($message)) {
                $logger->$action(json_encode($message, JSON_UNESCAPED_UNICODE), $context);
            } else {
                $logger->$action($message, $context);
            }
        });
    }
}

if (!function_exists('errorLogs')) {
    /**
     * 记录错误日志
     * @param $message
     */
    function errorLogs($message, string $name='info', array $context = []):void
    {
        logs($message, $name, $context, 'error');
    }
}

if (!function_exists('warningLogs')) {
    /**
     * 警告日志
     * @param $message
     */
    function warningLogs($message, string $name='info', array $context = []):void
    {
        logs($message, $name, $context, 'warning');
    }
}

if (!function_exists('debugLogs')) {
    /**
     * DEBUG日志
     * @param $message
     */
    function debugLogs($message, string $name='info', array $context = []):void
    {
        logs($message, $name, $context, 'debug');
    }
}

